package com.ctrip.corp.obt.shard.infrastructure;

import com.ctrip.corp.obt.generic.utils.Assert;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.shard.core.ShardDataSource;
import com.ctrip.corp.obt.shard.domain.ShardDataSourceMeta;
import com.ctrip.corp.obt.shard.domain.gateway.DataShardSourceGateway;
import lombok.RequiredArgsConstructor;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author marco.zheng
 * @version 1.0
 * @date 2022/03/15
 * @desc 聚合DataShardSource数据网关
 * @see
 * @since 1.0
 */
@RequiredArgsConstructor
public class AggregateDataShardSourceGateway implements DataShardSourceGateway {

    private final List<DataShardSourceGateway> dataShardSourceGatewayList;

    @Override
    public Set<ShardDataSource> getAllSource() {
        Set<ShardDataSource> result = new HashSet<>();
        for (DataShardSourceGateway dataShardSourceGateway : dataShardSourceGatewayList) {
            Set<ShardDataSource> allSources = dataShardSourceGateway.getAllSource();
            if (CollectionUtils.isNotEmpty(allSources)) {
                // 当未配置meta信息时，应剔除而不应该失败
                Set<ShardDataSource> sourceSet = allSources.stream()
                    .filter(source -> CollectionUtils.isNotEmpty(source.getMetas())).collect(Collectors.toSet());
                sourcePreCheck(sourceSet);
                result.addAll(sourceSet);
            }
        }
        return result;
    }

    @Override
    public Set<ShardDataSource> getSourceByTenantIds(Set<String> tenantIds) {
        if (CollectionUtils.isEmpty(tenantIds)) {
            return Collections.emptySet();
        }
        Set<ShardDataSource> allSource = new HashSet<>();
        for (DataShardSourceGateway dataShardSourceGateway : dataShardSourceGatewayList) {
            Set<ShardDataSource> sources = dataShardSourceGateway.getSourceByTenantIds(tenantIds);
            if (CollectionUtils.isNotEmpty(sources)) {
                allSource.addAll(sources);
            }
        }
        return allSource;
    }

    private void sourcePreCheck(Set<ShardDataSource> sources) {
        for (ShardDataSource source : sources) {
            String sourceType = source.getSource();
            Assert.notNull(source.getTenantId(), "Data shard source pre check failed: tenantId is null under sourceType: " + sourceType);
            for (ShardDataSourceMeta meta : source.getMetas()) {
                Assert.notNull(meta.getDriverClass(), "Data shard source pre check failed: driverClassName is null under sourceType: " + sourceType);
                Assert.notNull(meta.getUrl(), "Data shard source pre check failed: database url is null under sourceType: " + sourceType);
                Assert.notNull(meta.getUsername(), "Data shard source pre check failed: database username is null under sourceType: " + sourceType);
                Assert.notNull(meta.getPassword(), "Data shard source pre check failed: database password is null under sourceType: " + sourceType);
            }
        }
    }

}
